home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Communications / pop3d / Source / main.c < prev    next >
C/C++ Source or Header  |  1993-06-07  |  10KB  |  376 lines

  1. /*
  2.  *    pop3d        - IP/TCP/POP3 server for UNIX 4.3BSD
  3.  *              Post Office Protocol - Version 3 (RFC1225)
  4.  *
  5.  *      (C) Copyright 1991 Regents of the University of California
  6.  *
  7.  *      Permission to use, copy, modify, and distribute this program
  8.  *      for any purpose and without fee is hereby granted, provided
  9.  *      that this copyright and permission notice appear on all copies
  10.  *      and supporting documentation, the name of University of California
  11.  *      not be used in advertising or publicity pertaining to distribution
  12.  *      of the program without specific prior permission, and notice be
  13.  *      given in supporting documentation that copying and distribution is
  14.  *      by permission of the University of California.
  15.  *      The University of California makes no representations about
  16.  *      the suitability of this software for any purpose.  It is provided
  17.  *      "as is" without express or implied warranty.
  18.  *
  19.  *    Katie Stevens
  20.  *    dkstevens@ucdavis.edu
  21.  *     Information Technology -- Campus Access Point
  22.  *    University of California, Davis
  23.  *
  24.  **************************************
  25.  *
  26.  *    main.c
  27.  *
  28.  *    REVISIONS:
  29.  *        02-27-90 [ks]    original implementation
  30.  *    1.000    03-04-90 [ks]
  31.  *    1.001    06-24-90 [ks]    implement optional TOP command
  32.  *    1.002    07-22-91 [ks]    -- reset index counter after folder rewind
  33.  *                   in fld_release (Thanks to John Briggs,
  34.  *                   vaxs09@vitro.com, Vitro Corporation,
  35.  *                   Silver Spring, MD for finding this bug!)
  36.  *                -- set umask() value explicitly (Thanks to
  37.  *                   Vikas Aggarwal, JvNCnet, Princeton, NJ
  38.  *                   for suggesting this)
  39.  *    1.003    03-92    [ks]   close mailbox before return from main()
  40.  *    1.004   11-13-91 [ks]    leave original mailbox intact during POP
  41.  *                session (Thanks to Dave Cooley,
  42.  *                dwcooley@colby.edu for suggesting this)
  43.  */
  44.  
  45. #include <stdio.h>
  46. #include <signal.h>
  47. #include <ctype.h>
  48. #include <sys/param.h>
  49. #include "pop3.h"
  50.  
  51. #define VERSION        "1.004"
  52. #define REVDATE        "January, 1992"
  53.  
  54. char *svr_hostname;                /* Hostname of POP3 server */
  55. char svr_buf[SVR_BUFSIZ+2];            /* Buffer for server I/O */
  56. char cli_user[CLI_BUFSIZ];            /* Save client username */
  57.  
  58. static char *svr_invalid = "-ERR Invalid command; valid commands:";
  59.  
  60. #ifdef DEBUG
  61. FILE *logfp = NULL;                /* File for recording session */
  62. #endif
  63.  
  64. /* Routines in this file */
  65. static void initialize();
  66. static void svr_timeout();
  67. static void int_hangup();
  68. static void int_progerr();
  69.  
  70. static int svr_auth();
  71. static int svr_pass();
  72. static int svr_trans();
  73. static int svr_fold();
  74. static int svr_shutdown();
  75.  
  76. /**************************************************************************/
  77.  
  78. /* Initialize POP3 server */
  79. static void
  80. initialize()
  81. {
  82.     char buf[MAXHOSTNAMELEN+1];
  83.  
  84.     /* File permissions for owner only */
  85.     umask(077);        /* [1.002] */
  86.  
  87. #ifdef DEBUG
  88.     /* Prepare log file */
  89.     logfp = fopen(LOGFILE,"w");
  90.     fprintf(logfp,"POP3 server startup; version %s (%s)\n",
  91.         VERSION,REVDATE);
  92. #endif
  93.     /* Get our hostname */
  94.     gethostname(buf,MAXHOSTNAMELEN);
  95.     svr_hostname = malloc(strlen(buf) + 1);
  96.     if (svr_hostname == NULL)
  97.         fail(FAIL_OUT_OF_MEMORY);
  98.     strcpy(svr_hostname,buf);
  99.  
  100.     /* Handle process signals ourself */
  101.     signal(SIGALRM, svr_timeout);        /* timer expiration */
  102.  
  103.     signal(SIGHUP, int_hangup);        /* socket signals */
  104.     signal(SIGURG, int_hangup);
  105.     signal(SIGTERM, int_hangup);
  106.  
  107. #ifdef LINUX
  108. # ifdef SIGBUS
  109.     signal(SIGBUS, int_progerr);        /* fatal program errors */
  110. # endif
  111. #endif
  112.     signal(SIGSEGV, int_progerr);
  113.     signal(SIGILL, int_progerr);
  114.     signal(SIGIOT, int_progerr);
  115. }
  116.  
  117. /* Timeout while waiting for next client command */
  118. static void
  119. svr_timeout()
  120. {
  121.     fld_release();                /* Release mailbox folder */
  122.     fail(FAIL_LOST_CLIENT);            /* Exit POP3 server */
  123. }
  124. /* Timeout while waiting for next client command */
  125. static void
  126. int_hangup()
  127. {
  128.     fld_release();                /* Release mailbox folder */
  129.     fail(FAIL_HANGUP);            /* Exit POP3 server */
  130. }
  131. /* Timeout while waiting for next client command */
  132. static void
  133. int_progerr()
  134. {
  135.     fld_release();                /* Release mailbox folder */
  136.     fail(FAIL_PROGERR);            /* Exit POP3 server */
  137. }
  138.  
  139. /**************************************************************************/
  140.  
  141. /* Server Authentification State; process client USER command */
  142. static int
  143. svr_auth(state,inbuf)
  144. int state;
  145. char *inbuf;
  146. {
  147.     if (strncmp(inbuf,"quit",4) == 0)
  148.         return(svr_shutdown());
  149.     /* Expecting USER command */
  150.     if (strncmp(inbuf,"user",4) == 0) {
  151.         inbuf += 4;
  152.         EATSPACE(inbuf);
  153.         strcpy(cli_user,inbuf);
  154.         strcpy(svr_buf,"+OK please send PASS command\r\n");
  155.         state = SVR_PASS_STATE;
  156.     } else {
  157.         sprintf(svr_buf,"%s  USER,  QUIT\r\n",svr_invalid);
  158.     }
  159.     return(state);
  160. }
  161.  
  162. /* Server Password State; process client PASS command */
  163. static int
  164. svr_pass(state,inbuf)
  165. int state;
  166. char *inbuf;
  167. {
  168.     int cnt;
  169.  
  170.     if (strncmp(inbuf,"quit",4) == 0)
  171.         return(svr_shutdown());
  172.     /* Expecting PASS command */
  173.     if (strncmp(inbuf,"pass",4) != 0) {
  174.         sprintf(svr_buf,"%s  PASS,  QUIT\r\n",svr_invalid);
  175.         return(state);
  176.     }
  177.     /* Verify usercode/password pair */
  178.     inbuf += 4;
  179.     EATSPACE(inbuf);
  180.     if (verify_user(cli_user,inbuf) == -1) {
  181.         strcpy(svr_buf,"-ERR invalid usercode or password, please try again\r\n");
  182.         return(SVR_AUTH_STATE);
  183.     }
  184.     strcpy(svr_buf,DEF_MAIL_DIR);
  185.     strcat(svr_buf,cli_user);
  186.     return(fld_fromsp(svr_buf));
  187. }
  188.  
  189. /* Server Transaction State; process client mailbox command */
  190. static int
  191. svr_trans(state,inbuf)
  192. int state;
  193. char *inbuf;
  194. {
  195.     int msgnum;
  196.  
  197.     if (strncmp(inbuf,"quit",4) == 0)
  198.         return(svr_shutdown());
  199.     /* Expecting mailbox command */
  200.     if (strncmp(inbuf,"dele",4) == 0) {
  201.         inbuf += 4;
  202.         EATSPACE(inbuf);
  203.         if (*inbuf == NULL_CHAR)
  204.             sprintf(svr_buf,"-ERR message number required (e.g.  DELE 1)\r\n");
  205.         else
  206.             fld_delete(atoi(inbuf));
  207.     } else if (strncmp(inbuf,"host",4) == 0) {
  208.         inbuf += 4;
  209.         EATSPACE(inbuf);
  210.         if (*inbuf == NULL_CHAR)
  211.             sprintf(svr_buf,"-ERR must specify hostname\r\n");
  212.         else
  213.             state = fld_bsmtp(inbuf);
  214.     } else if (strncmp(inbuf,"last",4) == 0) {
  215.         fld_last();
  216.     } else if (strncmp(inbuf,"list",4) == 0) {
  217.         inbuf += 4;
  218.         EATSPACE(inbuf);
  219.         if (*inbuf == NULL_CHAR)
  220.             fld_list(-1);
  221.         else
  222.             fld_list(atoi(inbuf));
  223.     } else if (strncmp(inbuf,"mbox",4) == 0) {
  224.         inbuf += 4;
  225.         EATSPACE(inbuf);
  226.         if (*inbuf == NULL_CHAR)
  227.             sprintf(svr_buf,"-ERR must specify mailbox filename\r\n");
  228.         else
  229.             state = fld_fromsp(inbuf);
  230.     } else if (strncmp(inbuf,"noop",4) == 0) {
  231.         strcpy(svr_buf,"+OK\r\n");
  232.     } else if (strncmp(inbuf,"retr",4) == 0) {
  233.         inbuf += 4;
  234.         EATSPACE(inbuf);
  235.         if (*inbuf == NULL_CHAR) {
  236.             sprintf(svr_buf,"-ERR message number required (e.g.  RETR 1)\r\n");
  237.         } else
  238.             fld_retr(atoi(inbuf),-1);
  239.     } else if (strncmp(inbuf,"rset",4) == 0) {
  240.         fld_reset();
  241.     } else if (strncmp(inbuf,"stat",4) == 0) {
  242.         fld_stat();
  243.     } else if (strncmp(inbuf,"top",3) == 0) {
  244.         inbuf += 3;
  245.         EATSPACE(inbuf);
  246.         if (*inbuf == NULL_CHAR) {
  247.             sprintf(svr_buf,"-ERR message number and line count required (e.g.  TOP 1 7)\r\n");
  248.         } else {
  249.             msgnum = atoi(inbuf);
  250.             while (!isspace(*inbuf)) ++inbuf;
  251.             EATSPACE(inbuf);
  252.             if (*inbuf == NULL_CHAR)
  253.                 sprintf(svr_buf,"-ERR line count required (e.g.  TOP 1 7)\r\n");
  254.             else
  255.                 fld_retr(msgnum,atoi(inbuf));
  256.         }
  257.     } else {
  258.         sprintf(svr_buf,
  259.             "%s  DELE, HOST, LAST, LIST, MBOX, NOOP, RETR, RSET, STAT, TOP  or  QUIT\r\n",
  260.             svr_invalid);
  261.     }
  262.     return(state);
  263. }
  264.  
  265. /* Server Folder State; need to open another folder */
  266. static int
  267. svr_fold(state,inbuf)
  268. int state;
  269. char *inbuf;
  270. {
  271.     if (strncmp(inbuf,"quit",4) == 0)
  272.         return(svr_shutdown());
  273.     if (strncmp(inbuf,"host",4) == 0) {
  274.         inbuf += 4;
  275.         EATSPACE(inbuf);
  276.         state = fld_bsmtp(inbuf);
  277.     } else if (strncmp(inbuf,"mbox",4) == 0) {
  278.         inbuf += 4;
  279.         EATSPACE(inbuf);
  280.         state = fld_fromsp(inbuf);
  281.     } else if (strncmp(inbuf,"noop",4) == 0) {
  282.         strcpy(svr_buf,"+OK\r\n");
  283.     } else {
  284.         sprintf(svr_buf,"%s  HOST,  MBOX,  NOOP  or  QUIT\r\n",svr_invalid);
  285.     }
  286.     return(state);
  287. }
  288.  
  289. /* Prepare to shutdown POP3 server */
  290. static int
  291. svr_shutdown()
  292. {
  293.     fld_release();
  294.     sprintf(svr_buf,"+OK %s POP3 Server (Version %s) shutdown.\r\n",
  295.         svr_hostname,VERSION);
  296.     return(SVR_DONE_STATE);
  297. }
  298.  
  299. /**************************************/
  300.  
  301. void
  302. svr_data_out(buf)
  303. char *buf;
  304. {
  305.     /* Send out response to client */
  306.     alarm(SVR_TIMEOUT_SEND);
  307.     fputs(buf,stdout);
  308.     fflush(stdout);
  309.     alarm(0);
  310. }
  311.  
  312. /**************************************************************************/
  313.  
  314. main()
  315. {
  316.     int svr_state = SVR_LISTEN_STATE;    /* State of POP3 server */
  317.     char cli_buf[CLI_BUFSIZ];        /* Buffer for client cmds */
  318.  
  319.     initialize();
  320.  
  321.     fprintf(stdout,"+OK %s POP3 Server (Version %s) ready.\r\n",
  322.         svr_hostname,VERSION);
  323.     fflush(stdout);
  324.     svr_state = SVR_AUTH_STATE;
  325.     for ( ; ; ) {
  326.         /* Wait for command from client */
  327.         alarm(SVR_TIMEOUT_CLI);
  328.         if (fgetl(cli_buf,CLI_BUFSIZ,stdin) == NULL)
  329.             break;
  330.         alarm(0);
  331.  
  332.         /* Take action on client command */
  333.         cmd_prepare(cli_buf);
  334. #ifdef DEBUG
  335.         if ((cli_buf[0] == 'p')||(cli_buf[0] == 'P'))
  336.             fprintf(logfp,"CLI: PASS\n",cli_buf);
  337.         else
  338.             fprintf(logfp,"CLI: %s\n",cli_buf);
  339. #endif
  340.         switch(svr_state) {
  341.         case SVR_AUTH_STATE:    /* Expecting USER command */
  342.             svr_state = svr_auth(svr_state,cli_buf);
  343.             break;
  344.         case SVR_PASS_STATE:    /* Expecting PASS command */
  345.             svr_state = svr_pass(svr_state,cli_buf);
  346.             break;
  347.         case SVR_TRANS_STATE:    /* Expecting mailbox command */
  348.             svr_state = svr_trans(svr_state,cli_buf);
  349.             break;
  350.         case SVR_FOLD_STATE:    /* Need to open another mailbox */
  351.             svr_state = svr_fold(svr_state,cli_buf);
  352.             break;
  353.         default:
  354.             fail(FAIL_CONFUSION);        /* Wont return */
  355.             break;
  356.         }
  357. #ifdef DEBUG
  358.         fprintf(logfp,"SVR: %s",svr_buf);
  359. #endif
  360.  
  361.         /* Send out response to client */
  362.         alarm(SVR_TIMEOUT_SEND);
  363.         fputs(svr_buf,stdout);
  364.         fflush(stdout);
  365.         alarm(0);
  366.         if (ferror(stdout))
  367.             break;
  368.  
  369.         /* Exit when server has sent goodbye */
  370.         if (svr_state == SVR_DONE_STATE)
  371.             break;
  372.     }
  373.         fld_release();        /* [1.003] Make sure folder is released */
  374.     exit(0);
  375. }
  376.